home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C ++ / Applications / TimGA 1.2.1 / .cp / CPopulation.cp < prev    next >
Encoding:
Text File  |  1997-07-16  |  20.3 KB  |  754 lines  |  [TEXT/CWIE]

  1. // ===========================================================================
  2. //    CPopulation.cp        ©1995-97 Timo Eloranta        All rights reserved.
  3. // ===========================================================================
  4. //    CPopulation.h        (press Command-Tab to open the associated header)
  5.  
  6. #include <UDrawingState.h>
  7. #include <UDesktop.h>
  8.  
  9. #ifndef __TOOLUTILS__
  10. #include <ToolUtils.h>
  11. #endif
  12.  
  13. #include <profiler.h>
  14. #include <algorithm.h>        // MSL - sort
  15.  
  16. #include "CPopulation.h"
  17. #include "CGraphGAApp.h"
  18. #include "MyUtils.h"
  19. #include "GraphGA_PaneIDs.h"
  20. #include "LAnimateCursor.h"
  21.  
  22. // ---------------------------------------------------------------------------
  23. //        • ~CPopulation
  24. // ---------------------------------------------------------------------------
  25. //    Destructor.
  26.  
  27. CPopulation::~CPopulation()
  28. {
  29.     JunkGraphs();
  30. }
  31.  
  32. // ---------------------------------------------------------------------------
  33. //        • JunkGraphs
  34. //
  35. //          Called by:    CPopulation::~CPopulation
  36. // ---------------------------------------------------------------------------
  37.  
  38. void
  39. CPopulation::JunkGraphs()
  40. {
  41.     // Get rid of the graphs (chromosomes)
  42.  
  43.     GraphPtrVector::iterator    theIter = mDrawings.begin();
  44.     
  45.     while ( theIter != mDrawings.end() ) {
  46.         delete *theIter;
  47.         ++theIter;
  48.     }
  49.     
  50.     mDrawings.erase( mDrawings.begin(), mDrawings.end() );
  51. }
  52.  
  53. // ---------------------------------------------------------------------------
  54. //        • Initialize
  55. //
  56. //          Called by:    CGraphGADoc::CGraphGADoc
  57. //                        CGraphGADoc::ObeyCommand
  58. // ---------------------------------------------------------------------------
  59.  
  60. void
  61. CPopulation::Initialize(
  62.     Boolean                inFirstTime,
  63.     SGraphSize            *inGraphSize,
  64.     SNodePairVector        *inEdgeArray )
  65. {
  66.     Int16            theIndex;
  67.     CGraphPtr        theGraph;
  68.     
  69.     mCurGeneration    = 0L;
  70.     mRunningTime    = 0;
  71.     
  72.     // Use "spin cursor" since this can take a while...
  73.     LAnimateCursor    theSpinCursor( curs_First, curs_Qty );
  74.     
  75.     if ( inFirstTime ) {
  76.  
  77.         mNodeCount    = inGraphSize -> nodes;
  78.         mEdgeCount    = inGraphSize -> edges;
  79.  
  80.         mSelectionArray.reserve( mPopSize + 1 );
  81.     
  82.         // Create the list of graph drawings with randomly placed nodes
  83.         for ( theIndex = 1; theIndex <= mPopSize; ++theIndex ) {
  84.     
  85.             theGraph = new CGraphDrawing;
  86.             if ( theGraph ) {
  87.                 theSpinCursor.Set();
  88.                 theGraph -> Initialize( mNodeCount, mEdgeCount, 
  89.                                         mGridSize, true );
  90.             
  91.                 mDrawings.push_back( theGraph );
  92.             }
  93.         }
  94.         
  95.         // Initialize the two extra graphs which are used in crossover
  96.         // They don't actually need the randomly placed nodes, but
  97.         // we'll throw them away later (in CGraphNodes::Crossover) ...
  98.         mCrossTemp1.Initialize( mNodeCount, mEdgeCount, mGridSize, true );
  99.         mCrossTemp2.Initialize( mNodeCount, mEdgeCount, mGridSize, true );
  100.  
  101.         if ( mEdgeCount > 36 )
  102.             AddCrossMemories();
  103.  
  104.         SetUpEdges( inEdgeArray );    
  105.         
  106.     } else {    // We already have a list of drawings. 
  107.                 // We just want to reshuffle the positions of the nodes.
  108.  
  109.         GraphPtrVector::iterator    theIter = mDrawings.begin();
  110.  
  111.         while ( theIter != mDrawings.end() ) {
  112.             theSpinCursor.Set();
  113.             (**theIter).Initialize( mNodeCount, mEdgeCount, mGridSize, false );
  114.             ++theIter;
  115.         }
  116.     }
  117.         
  118.     InitBestEver();
  119.     
  120.     Evaluate( &theSpinCursor );        // Evaluation of the initial population
  121. }
  122.  
  123. // ---------------------------------------------------------------------------
  124. //        • AddCrossMemories    (PRIVATE)
  125. //
  126. //          Called by:    CPopulation::Initialize
  127. // ---------------------------------------------------------------------------
  128. // Try adding a "cross memory" to every drawing. If any of the drawings fail
  129. // to get a memory (if there isn't enough memory...), remove memories from
  130. // all the drawings!
  131. //
  132. // Note: mBestEver, mCrossTemp1 & mCrossTemp2 don't need cross memories
  133.  
  134. void
  135. CPopulation::AddCrossMemories()
  136. {
  137.     GraphPtrVector::iterator    theIter = mDrawings.begin();
  138.  
  139.     Try_ {    
  140.         while ( theIter != mDrawings.end() ) {
  141.             (*theIter) -> AddCrossMemory();
  142.             ++theIter;
  143.         }
  144.     }
  145.             
  146.     Catch_( inErr ) {
  147.         theIter = mDrawings.begin();
  148.         
  149.         while ( theIter != mDrawings.end() ) {
  150.             (*theIter) -> JunkCrossMemory();
  151.             ++theIter;
  152.         }
  153.         
  154.         if ( mEdgeCount <= 256 ) {
  155.             UDesktop::Deactivate();
  156.             ::NoteAlert( ALRT_Memory, nil );
  157.             UDesktop::Activate();
  158.         }
  159.         
  160.     } EndCatch_
  161. }
  162.  
  163. // ---------------------------------------------------------------------------
  164. //        • SetUpEdges    (PRIVATE)
  165. //
  166. //          Called by:    CPopulation::Initialize
  167. // ---------------------------------------------------------------------------
  168.  
  169. void
  170. CPopulation::SetUpEdges( SNodePairVector    *inEdgeArray )
  171. {
  172.     Int16            theIndex,
  173.                     theNodeNbr1, theNodeNbr2;
  174.     CGraphPtr        theFirstGraph;
  175.     Boolean            theRandomEdges = (! inEdgeArray );
  176.     
  177.     theFirstGraph = mDrawings.front();
  178.  
  179.     theIndex = 1;
  180.     while (theIndex <= mEdgeCount) {    // Add edges to graph drawings
  181.  
  182.         if ( theRandomEdges ) {            // Are the nodes picked randomly?
  183.             theNodeNbr1 = RangedRdm( 1, mNodeCount );
  184.             theNodeNbr2 = RangedRdm( 1, mNodeCount );
  185.         } else {
  186.             theNodeNbr1 = (*inEdgeArray)[ theIndex ].nodeNbr1;
  187.             theNodeNbr2 = (*inEdgeArray)[ theIndex ].nodeNbr2;
  188.         }
  189.         
  190.         if ( theNodeNbr1 != theNodeNbr2 ) {
  191.         
  192.             // If necessary, test with the 1st graph  
  193.             // whether this edge will do...
  194.             if ( (! theRandomEdges ) || (theFirstGraph -> 
  195.                     ValidNewEdge( theNodeNbr1, theNodeNbr2 )) ) {
  196.     
  197.                 // Iterate through all the graphs and insert 
  198.                 // the new *same* edge to everyone of them...
  199.                 // Note: mCrossTemp1 and mCrossTemp2 need no edges!
  200.     
  201.                 GraphPtrVector::iterator    theIter = mDrawings.begin();
  202.     
  203.                 while ( theIter != mDrawings.end() ) { 
  204.                     (*theIter) -> SetNewEdge( theIndex,
  205.                                               theNodeNbr1, theNodeNbr2);
  206.                     ++theIter;
  207.                 }
  208.  
  209.                 ++theIndex;                // One edge done, many to go...
  210.             }
  211.         }
  212.     }
  213. }
  214.  
  215. // ---------------------------------------------------------------------------
  216. //        • InitSelectionArray    (PRIVATE)
  217. //
  218. //          Called by:    CPopulation::SetSelection
  219. // ---------------------------------------------------------------------------
  220. //  The last value (mSelectionArray[ mPopSize ]) is always 100. 
  221. //  The Nth value = the (N+1)th value + 
  222. //                    the max( 100 - (mPopSize - N) * mSelection.step,
  223. //                             mSelection.min )
  224. //
  225. //  Example.  mPopSize: 8, mSelection.step: 15, mSelection.min: 20
  226. //                 (the array is filled starting from the end!)
  227. //
  228. //  --->         increase: { -,  20,  20,  25,  40,  55,  70,  85, 100 }
  229. //  --->  mSelectionArray: { 0, 415, 395, 375, 350, 310, 255, 185, 100 }
  230.  
  231. void
  232. CPopulation::InitSelectionArray()
  233. {
  234.     Int16    theDex, theElevator = 100;
  235.             
  236.     mSelectionArray[ 0 ] = 0;
  237.     
  238.     // If the user hasn't set a step then we'll count one
  239.     
  240.     if ( mSelection.autom )
  241.         mSelection.step = AutomSelectionStep( mSelection.min, mPopSize );
  242.     
  243.     for ( theDex = mPopSize; theDex >= 1; theDex-- ) {
  244.         if ( theDex == mPopSize )
  245.             mSelectionArray[theDex]    = 100;
  246.         else
  247.             mSelectionArray[theDex]    = mSelectionArray[ theDex + 1 ] + 
  248.                                       max( theElevator, mSelection.min );
  249.  
  250.         theElevator -= mSelection.step;
  251.     }
  252. }
  253.  
  254. // ---------------------------------------------------------------------------
  255. //        • AutomSelectionStep
  256. //
  257. //          Called by:    CPopulation::InitSelectionArray
  258. //                        CSelectionDialog::SetValues
  259. //                        CSelectionDialog::ListenToMessage
  260. // ---------------------------------------------------------------------------
  261.  
  262. Int16
  263. AutomSelectionStep(
  264.     Int16    inSelectionMinimum,
  265.     Int16    inPopSize )
  266. {
  267.     return    (2 * (100 - inSelectionMinimum) ) / inPopSize;
  268. }
  269.  
  270. // ---------------------------------------------------------------------------
  271. //        • InitBestEver    (PRIVATE)
  272. //
  273. //          Called by:    CPopulation::Initialize
  274. // ---------------------------------------------------------------------------
  275.  
  276. void
  277. CPopulation::InitBestEver()
  278. {
  279.     CGraphPtr    theFirstGraph;
  280.     CFitness    theDummyFitness;
  281.     
  282.     // Copy one (= 1st) of the graphs to be the initial best ever,
  283.     // but before that evaluate the graph so that the best ever
  284.     // doesn't need to be evaluated...
  285.  
  286.     theFirstGraph = mDrawings.front();
  287.     theFirstGraph -> GetFitness( theDummyFitness, max_Int32 );
  288.  
  289.     mBestEver.BestCopy( *theFirstGraph, true );
  290.  
  291.     mBestGeneration    = 0L;
  292.     mBestTime        = 0L;
  293. }
  294.  
  295. // ---------------------------------------------------------------------------
  296. //        • Evaluate
  297. //
  298. //          Called by:    CPopulation::Initialize
  299. //                        CPopulation::DoOneIteration
  300. // ---------------------------------------------------------------------------
  301.  
  302. Boolean
  303. CPopulation::Evaluate( 
  304.     LAnimateCursor *inSpinCursor )
  305. {
  306.     CGraphPtr    theNewChamp = nil;
  307.     CFitness    theFitness, theCurHScore;
  308.     Int32        theCrossings, theCrossingsSum = 0;
  309.  
  310.     GraphPtrVector::iterator    theIter = mDrawings.begin();
  311.     
  312.     mLeastCrossings    = max_Int32;
  313.     
  314.     mBestEver.GetFitness( theCurHScore );
  315.     
  316.     while ( theIter != mDrawings.end() ) {
  317.     
  318.         if ( inSpinCursor )
  319.             inSpinCursor -> Set();
  320.     
  321.         (*theIter) -> GetFitness( theFitness, mLeastCrossings );
  322.  
  323.         theCrossings = theFitness.GetCrossings();
  324.         
  325.         if ( theCrossings < mLeastCrossings )
  326.             mLeastCrossings = theCrossings;
  327.             
  328.         theCrossingsSum    += theCrossings;
  329.         
  330.         if ( theCurHScore < theFitness ) {
  331.             theCurHScore = theFitness;
  332.             theNewChamp  = *theIter;
  333.         }
  334.         ++theIter;
  335.     }
  336.     
  337.     mAvgCrossings = (mPopSize > 0) ? (theCrossingsSum / mPopSize) : -1;
  338.     
  339.     if ( theNewChamp ) {
  340.         mBestEver.BestCopy( *theNewChamp, false );
  341.         
  342.         return true;    // The best ever changed !!
  343.     }
  344.     return false;        // The best ever didn't change...
  345. }
  346.  
  347. // ---------------------------------------------------------------------------
  348. //        • DoIterate
  349. //
  350. //          Called by:    CGraphGADoc::SpendTime
  351. // ---------------------------------------------------------------------------
  352. //  Spend time iterating. Exit if 
  353. //      A) the time specified in inMaxSpendTimeOnce is reached 
  354. //     or B) our termination condition for iteration is filled.
  355. //
  356. //  Pass back whether we stopped because the termination condition was
  357. //  reached (outGameIsOver) and also if we found a new best solution
  358. //  (outThereIsANewKing).
  359.  
  360. void
  361. CPopulation::DoIterate( 
  362.     Boolean &outGameIsOver,
  363.     Boolean &outThereIsANewKing,
  364.     Int16    inMaxSpendTimeOnce  )
  365. {
  366.     Int32        theSessionStartingTicks, theIterStartingTicks, theTimeNow;
  367.     Boolean        theTimeIsOut = false;
  368.             
  369.     theSessionStartingTicks = ::TickCount();
  370.     
  371.     // We go for another iteration if the termination condition is not
  372.     // filled and we haven't ran out of time...
  373.     
  374.     while (     (! (outGameIsOver = ( mTermCondExists && 
  375.                                      TerminationCondition() )))
  376.             && 
  377.                 (! theTimeIsOut) 
  378.           ) {
  379.  
  380.         // Another iteration is wanted. So, let's do one!
  381.         // Before we go, we'll start the clock...
  382.         
  383.         theIterStartingTicks     = ::TickCount();
  384.  
  385.         #if __profile__
  386.         ProfilerSetStatus( true );    // ••• Start profiling •••
  387.         #endif
  388.  
  389.         if ( DoOneIteration() )    {    
  390.             outThereIsANewKing     = true;            // A new "best ever" was found
  391.             mBestGeneration     = mCurGeneration;
  392.         }
  393.  
  394.         #if __profile__        
  395.         ProfilerSetStatus( false );    // ••• Stop profiling •••
  396.         #endif        
  397.  
  398.         theTimeNow = ::TickCount();
  399.         
  400.         // Add the time of last iteration to the total
  401.         mRunningTime +=    theTimeNow - theIterStartingTicks;        
  402.         
  403.         if ( mBestGeneration == mCurGeneration ) 
  404.             mBestTime = mRunningTime;
  405.                                     
  406.         // Check if we've already spent enough time for one "session"
  407.         theTimeIsOut = 
  408.             ( ( theTimeNow - theSessionStartingTicks) > inMaxSpendTimeOnce );
  409.     }
  410. }
  411.  
  412. // ---------------------------------------------------------------------------
  413. //        • DoOneIteration    (PRIVATE)
  414. //
  415. //          Called by:    CPopulation::DoIterate
  416. // ---------------------------------------------------------------------------
  417.  
  418. Boolean
  419. CPopulation::DoOneIteration( )
  420. {
  421.     mCurGeneration++;
  422.  
  423.     DoSelection();
  424.  
  425.     DoCrossover();
  426.     DoMutate();
  427.  
  428.     return Evaluate();
  429. }
  430.  
  431. // ---------------------------------------------------------------------------
  432. //        • DoSelection    (PRIVATE)
  433. //
  434. //          Called by:    CPopulation::DoOneIteration
  435. // ---------------------------------------------------------------------------
  436. //  Select surviving chromosomes using linear normalization (+ elitism)
  437.  
  438. void
  439. CPopulation::DoSelection( )
  440. {
  441.     UInt16Vector        theDyingOnes;
  442.     UInt16Vector        theSelectionCounts( mPopSize + 1, 0 );
  443.     Int16                theSelectCount = mPopSize,
  444.                         theCount, theIndex, theCloneIndex;
  445.     
  446.     CGraphPtr            theGraph1, theGraph2;
  447.  
  448.     // We'll start by sorting the list of graph drawings
  449.     sort(
  450.         mDrawings.begin(),
  451.         mDrawings.end(),
  452.         mComparator
  453.         );
  454.  
  455.     // If elitism is used, we'll make sure that the best won't get dropped!
  456.     // The best is situated at the end of the sorted list...
  457.     if ( mSelection.elitism ) {
  458.         theSelectionCounts[ mPopSize ] = 1;
  459.         theSelectCount--;
  460.     }
  461.  
  462.     // Use random numbers to choose the new intermediate population.
  463.     // Keep track of how many selections each chromosome gets.    
  464.     for ( theCount = 0; theCount < theSelectCount; ++theCount )
  465.         ++theSelectionCounts[ SelectOne() ];
  466.  
  467.     // Collect the ones that got no selections to the "list of death"...
  468.     for ( theIndex = 1; theIndex <= mPopSize; ++theIndex )
  469.         if ( ! theSelectionCounts[ theIndex ] ) 
  470.             theDyingOnes.push_back( theIndex );
  471.             
  472.     // Finally go through the selection array and copy ones 
  473.     // with >1 selections to the places of the ones with no future...
  474.     for ( theIndex = 1; theIndex <= mPopSize; ++theIndex ) {
  475.         
  476.         if ( theSelectionCounts[ theIndex ] ) {
  477.             theGraph1 = mDrawings[ theIndex - 1 ];
  478.             theGraph1 -> SetSelectionOriginal( theIndex );
  479.             
  480.             while (    theSelectionCounts[ theIndex ] > 1 ) {
  481.                 theCloneIndex = theDyingOnes.back();
  482.                 theDyingOnes.pop_back();
  483.                 theGraph2 = mDrawings[ theCloneIndex - 1 ];
  484.                 theGraph2 -> RuntimeCopy( *theGraph1, true );    // Clone !
  485.                 
  486.                 theSelectionCounts[ theIndex ]--;
  487.             }
  488.         }
  489.     }
  490. }
  491.  
  492. // ---------------------------------------------------------------------------
  493. //        • SelectOne        (PRIVATE)
  494. //
  495. //          Called by:    CPopulation::DoSelection
  496. // ---------------------------------------------------------------------------
  497.  
  498. Int16
  499. CPopulation::SelectOne( )
  500. {
  501.     Int16    theRandomNbr, 
  502.             theGraphNbr = mPopSize;
  503.  
  504.     // mSelectionArray[1] holds the cumulative sum of all
  505.     // the items in the selection array...
  506.     theRandomNbr = RangedRdm( 1, mSelectionArray[ 1 ] );
  507.     
  508.     while ( mSelectionArray[ theGraphNbr ] < theRandomNbr )
  509.         theGraphNbr--;
  510.         
  511.     return theGraphNbr;
  512. }
  513.  
  514. // ---------------------------------------------------------------------------
  515. //        • DoMutate        (PRIVATE)
  516. //
  517. //          Called by:    CPopulation::DoOneIteration
  518. // ---------------------------------------------------------------------------
  519.  
  520. void
  521. CPopulation::DoMutate( )
  522. {
  523.     GraphPtrVector::iterator    theIter = mDrawings.begin();
  524.     GraphPtrVector::iterator    theEnd;
  525.  
  526.     // If elitism is used then we protect the best chromosome
  527.     
  528.     if ( mSelection.elitism )
  529.         theEnd = &mDrawings.back();
  530.     else
  531.         theEnd = mDrawings.end();
  532.     
  533.     while ( theIter != theEnd ) {
  534.         if ( mMutationProb > FastRandom(100) )
  535.             (*theIter) -> Mutate();
  536.             ++theIter; 
  537.     }
  538. }
  539.  
  540. // ---------------------------------------------------------------------------
  541. //        • DoCrossover    (PRIVATE)
  542. //
  543. //          Called by:    CPopulation::DoOneIteration
  544. // ---------------------------------------------------------------------------
  545.  
  546. void
  547. CPopulation::DoCrossover( )
  548. {
  549.     CGraphPtr            theCrosser1, theCrosser2;
  550.     GraphPtrVector        theCrossers;
  551.     Int32                theCrosserCount = 0, theIndex;
  552.  
  553.     GraphPtrVector::iterator    theIter = mDrawings.begin();
  554.     GraphPtrVector::iterator    theEnd;
  555.  
  556.     // We start by selecting the graph drawings which 
  557.     // will take part in this phase.
  558.  
  559.     // If elitism is used then we protect the best chromosome
  560.     
  561.     if ( mSelection.elitism )
  562.         theEnd = &mDrawings.back();
  563.     else
  564.         theEnd = mDrawings.end();
  565.     
  566.     while ( theIter != theEnd ) {
  567.         if ( mCrossoverProb > FastRandom(100) )
  568.             theCrossers.push_back( *theIter );
  569.         ++theIter;
  570.     }
  571.  
  572.     // We need an even number of graphs! If we have an odd number,
  573.     // then just throw one away by random...
  574.     
  575.     theCrosserCount = theCrossers.size();
  576.     if ( theCrosserCount % 2 ) {
  577.         theCrossers.erase( theCrossers.begin() + FastRandom( theCrosserCount ));
  578.         theCrosserCount--;
  579.     }
  580.     
  581.     // Now we start pairing the chromosomes (=graphs) and crossing
  582.     // them over. Every graph takes part in max one crossover...
  583.     
  584.     while ( theCrosserCount > 1 ) {
  585.         
  586.         theCrosser1 = theCrossers[ theIndex = FastRandom( theCrosserCount ) ];
  587.         theCrossers.erase( theCrossers.begin() + theIndex );
  588.         theCrosserCount--; 
  589.         theCrosser2 = theCrossers[ theIndex = FastRandom( theCrosserCount ) ];
  590.         theCrossers.erase( theCrossers.begin() + theIndex );
  591.         theCrosserCount--;
  592.         
  593.         // Now we have two graphs in theCrosser1 and theCrosser2.
  594.         // We cross them only if they are not the one and same
  595.         // (this is possible if they are duplicates from the selection...).
  596.         
  597.         if ( (theCrosser1 -> GetSelectionOriginal()) !=
  598.              (theCrosser2 -> GetSelectionOriginal()) ) {
  599.             
  600.             if ( RandomBool() )
  601.                 theCrosser1 -> ThreeNodeCrossover( theCrosser2 );    // 50 %
  602.             else
  603.                 DoRectCrossover( theCrosser1, theCrosser2 );        // 50 %
  604.         }
  605.     }
  606. }
  607.  
  608. // ---------------------------------------------------------------------------
  609. //        • DoRectCrossover    (PRIVATE)
  610. //
  611. //          Called by:    CPopulation::DoCrossover
  612. // ---------------------------------------------------------------------------
  613.  
  614. void
  615. CPopulation::DoRectCrossover(
  616.     CGraphPtr inCrosser1,
  617.     CGraphPtr inCrosser2 )
  618. {
  619.     Int16    theW, theH;                    // = width and height of rect
  620.     Rect    theSourceRect, theDestRect;
  621.  
  622.     // Next we'll choose the "crossover rects". We'll restrict 
  623.     // both width and height of the rect to one-third-of-a-grid.
  624.     
  625.     if ( mGridSize < 6 )
  626.         theW = theH = 1;
  627.     else { 
  628.         theW = RangedRdm( 1, mGridSize / 3 );
  629.         theH = RangedRdm( 1, mGridSize / 3 );
  630.     }
  631.  
  632.     theSourceRect.left     = RangedRdm( 1, mGridSize - theW + 1 );
  633.     theSourceRect.right     = theSourceRect.left + theW - 1; 
  634.     theSourceRect.top     = RangedRdm( 1, mGridSize - theH + 1 );
  635.     theSourceRect.bottom = theSourceRect.top + theH - 1; 
  636.      
  637.     // We give a 50/50 chance for the destination rectangle
  638.     // to be totally random or the same as the source rect...
  639.      
  640.     if ( RandomBool() ) {
  641.      
  642.         theDestRect.left    = RangedRdm( 1, mGridSize - theW + 1 );
  643.         theDestRect.right    = theDestRect.left + theW - 1;
  644.         theDestRect.top        = RangedRdm( 1, mGridSize - theH + 1 );
  645.         theDestRect.bottom    = theDestRect.top + theH  - 1;
  646.          
  647.     } else
  648.         theDestRect    = theSourceRect;
  649.      
  650.     // Cross em'!
  651.     mCrossTemp1.RectCrossover( theSourceRect, theDestRect,
  652.                                  *inCrosser1, *inCrosser2 );
  653.     mCrossTemp2.RectCrossover( theSourceRect, theDestRect,
  654.                                  *inCrosser2, *inCrosser1 );
  655.      
  656.     // Copy the temp graphs to the real ones... 
  657.     inCrosser1 -> RuntimeCopy( mCrossTemp1, false );
  658.     inCrosser2 -> RuntimeCopy( mCrossTemp2, false );
  659. }
  660.  
  661. // ---------------------------------------------------------------------------
  662. //        • TerminationCondition    (PRIVATE)
  663. //
  664. //          Called by:    CPopulation::DoIterate
  665. // ---------------------------------------------------------------------------
  666.  
  667. Boolean
  668. CPopulation::TerminationCondition( )
  669. {
  670.     return (
  671.  
  672.         ( mTermination.stopMaxGenTotal &&
  673.           mCurGeneration >= mTermination.maxGenTotal ) ||
  674.  
  675.         ( mTermination.stopMaxGenNoChange &&
  676.           mCurGeneration - mBestGeneration >= mTermination.maxGenNoChange ) ||
  677.  
  678.         ( mTermination.stopMaxTimeTotal &&
  679.           mRunningTime >= mTermination.maxTimeTotal ) ||
  680.  
  681.         ( mTermination.stopMaxTimeNoChange &&
  682.           mRunningTime - mBestTime >= mTermination.maxTimeNoChange ) ||
  683.  
  684.         ( mTermination.stopNoCrossings &&
  685.           mLeastCrossings == 0L )
  686.           
  687.           );
  688. }
  689.  
  690. // ---------------------------------------------------------------------------
  691. //        • SetTermination
  692. //
  693. //          Called by:    CGraphGADoc::CGraphGADoc
  694. //                        CGraphGADoc::SetPopTermination
  695. // ---------------------------------------------------------------------------
  696.  
  697. void
  698. CPopulation::SetTermination( STermination &inTermination )
  699. {
  700.     mTermination    = inTermination;
  701.     
  702.     mTermCondExists = (    mTermination.stopMaxGenTotal ||
  703.                         mTermination.stopMaxGenNoChange ||
  704.                         mTermination.stopMaxTimeTotal ||
  705.                         mTermination.stopMaxTimeNoChange ||
  706.                         mTermination.stopNoCrossings 
  707.                       );
  708. }
  709.  
  710. // ---------------------------------------------------------------------------
  711. //        • SetProbabilities
  712. //
  713. //          Called by:    CGraphGADoc::CGraphGADoc
  714. //                        CGraphGADoc::SetPopProbabilities
  715. // ---------------------------------------------------------------------------
  716.  
  717. void
  718. CPopulation::SetProbabilities( 
  719.     Int16 inCrossoverProb,
  720.     Int16 inMutationProb )
  721. {
  722.     mCrossoverProb    = inCrossoverProb;
  723.     mMutationProb    = inMutationProb;
  724. }
  725.  
  726. // ---------------------------------------------------------------------------
  727. //        • SetSelection
  728. //
  729. //          Called by:    CGraphGADoc::CGraphGADoc
  730. //                        CGraphGADoc::ObeyCommand
  731. // ---------------------------------------------------------------------------
  732.  
  733. void
  734. CPopulation::SetSelection( SSelection &inSelection ) 
  735. {
  736.     mSelection = inSelection;
  737.     
  738.     InitSelectionArray();
  739. }
  740.  
  741. // ---------------------------------------------------------------------------
  742. //        • SetSizes
  743. //
  744. //          Called by:    CGraphGADoc::CGraphGADoc
  745. // ---------------------------------------------------------------------------
  746.  
  747. void
  748. CPopulation::SetSizes(
  749.     Int16    inGridSize,
  750.     Int16    inPopSize )
  751. {
  752.     mGridSize    = inGridSize;
  753.     mPopSize    = inPopSize;    
  754. }